package ck_validate

import (
	"errors"
	"fmt"
	"github.com/go-playground/form/v4"
	zhongwen "github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	zh2 "github.com/go-playground/validator/v10/translations/zh"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

type ZhValidate struct {
	Validate *validator.Validate
	Trans    ut.Translator
}

func (v *ZhValidate) Struct(s interface{}) error {
	err := v.Validate.Struct(s)
	if err != nil {
		errs := err.(validator.ValidationErrors)
		message := make([]string, 0, len(errs))
		p := reflect.TypeOf(s).Elem()
		for _, fieldError := range errs {
			if field, get := p.FieldByName(fieldError.StructField()); get {
				if msg := field.Tag.Get("message"); msg != "" {
					if validate := field.Tag.Get("validate"); validate != "" {
						msgSlice := strings.Split(msg, ",")
						msgIndex := 0
						//过滤omitempty,dive
						trueValidate := make([]string, 0)
						for _, ss := range strings.Split(validate, ",") {
							if ss != "omitempty" && ss != "dive" {
								trueValidate = append(trueValidate, ss)
							}
						}
						for i, ss := range trueValidate {
							if strings.Contains(ss, fieldError.Tag()) {
								msgIndex = i
								break
							}
						}
						if (len(msgSlice) >= (msgIndex + 1)) && (msgIndex >= 0) {
							message = append(message, msgSlice[msgIndex])
						}
					}
				} else {
					message = append(message, fieldError.Translate(v.Trans))
				}
			}
		}
		if len(message) == 0 {
			return err
		}
		return errors.New(strings.Join(message, ","))
	}
	return nil
}

func (v *ZhValidate) Decode(s interface{}, input url.Values) error {
	err := FormDecoder.Decode(s, input)
	if err != nil {
		return err
	}
	return v.Struct(s)
}

var Validate = initValidate()

var EditValidate = initEditValidate()

var FormDecoder *form.Decoder

func init() {
	FormDecoder = form.NewDecoder()
}

func initValidate() *ZhValidate {
	validate := validator.New()
	err := validate.RegisterValidation("defaultValue", defaultValue)
	if err != nil {
		fmt.Println("validator-error:自定义方法注册失败")
	}
	if err = validate.RegisterValidation("mobile", ValidateMobile); err != nil {
		fmt.Println("validator-error:手机号校验注册失败")
	}

	zh := zhongwen.New()
	uni := ut.New(zh, zh)
	trans, _ := uni.GetTranslator("zh")
	zh2.RegisterDefaultTranslations(validate, trans)
	return &ZhValidate{
		Validate: validate,
		Trans:    trans,
	}
}

func initEditValidate() *ZhValidate {
	EditValidate := validator.New()
	zh := zhongwen.New()
	uni := ut.New(zh, zh)
	trans, _ := uni.GetTranslator("zh")
	EditValidate.SetTagName("edit_validate")
	zh2.RegisterDefaultTranslations(EditValidate, trans)
	return &ZhValidate{
		Validate: EditValidate,
		Trans:    trans,
	}
}

//自定义校验函数-默认值设置  TestParam string `form:"testParam" validate:"defaultValue=abc,required" `
//	用法 defaultValue='abc' ;  defaultValue=abc,默认值标签尽量放第一个验证位置
func defaultValue(f validator.FieldLevel) bool {
	if f.Field().IsZero() {
		dataType := f.Field().Kind().String()
		dataDefault := f.Param()
		// 将[']符号替换为空
		dataDefault = strings.Replace(dataDefault, "'", "", -1)
		if dataDefault == "" {
			return true
		}
		// string
		if dataType == reflect.String.String() {
			f.Field().SetString(dataDefault)
		}
		// Int, Int8, Int16, Int32, or Int64
		if dataType == reflect.Int.String() ||
			dataType == reflect.Int8.String() ||
			dataType == reflect.Int16.String() ||
			dataType == reflect.Int32.String() ||
			dataType == reflect.Int64.String() {
			intValue, err := strconv.ParseInt(dataDefault, 10, 64)
			if err != nil {
				intValue = 0
			}
			f.Field().SetInt(intValue)
		}
		// bool
		if dataType == reflect.Bool.String() {
			f.Field().SetBool(parseBool(dataDefault))
		}
		// Float32 Float64
		if dataType == reflect.Float32.String() ||
			dataType == reflect.Float64.String() {
			floatValue, err := strconv.ParseFloat(dataDefault, 64)
			if err != nil {
				floatValue = 0
			}
			f.Field().SetFloat(floatValue)
		}
		// Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64
		if dataType == reflect.Uint.String() ||
			dataType == reflect.Uintptr.String() ||
			dataType == reflect.Uint8.String() ||
			dataType == reflect.Uint16.String() ||
			dataType == reflect.Uint32.String() ||
			dataType == reflect.Uint64.String() {
			intValue, err := strconv.Atoi(dataDefault)
			if err != nil {
				intValue = 0
			}
			uintValue := uint64(intValue)
			f.Field().SetUint(uintValue)
		}
	}
	return true
}
func parseBool(str string) bool {
	switch str {
	case "1", "t", "T", "true", "TRUE", "True":
		return true
	case "0", "f", "F", "false", "FALSE", "False":
		return false
	}
	return false
}

//ValidateMobile 手机号校验
func ValidateMobile(fl validator.FieldLevel) bool {
	return regexp.MustCompile(`^1[0-9]\d{9}$`).MatchString(fl.Field().String())
}
